Transcrição
Vamos melhorar a experiência do usuário em nossa aplicação. Atualmente temos 12 imagens em exibição na página; e se futuramente tivermos 100, 200? Seria interessante darmos ao usuário a opção de filtrar, por exemplo. Sabemos que cada objeto utilizado para a construção destes componentes possui a propriedade description, a ideia é colocarmos um campo de filtro no qual digitaremos parte do texto que está nesta descrição, e todas as imagens que a possuírem serão exibidas, enquanto as demais serão omitidas da página.
Em photo-list.component.html, que envolve o componente que traz os dados e os disponibiliza para photos.component.html, componente que os renderiza usando o grid do Bootstrap, acrescentaremos o seguinte trecho:
<div class="text-center mt-3 mb-3">
<form>
<input
class="rounded"
type="search"
placeholder="search..."
autofocus>
</form>
</div>Com isso, o <input> ficará centralizado na <div> e terá bordas arredondadas (rounded), será do tipo search, e possuirá foco assim que a página for carregada. E as classes mt-3 e mb-3 implicam nas margens de topo e de baixo, ambas com valor 3, valor arbitrário do Bootstrap. Salvaremos e voltaremos ao navegador, com o campo de busca implementado, porém ainda não pronto para uso.
De que maneira capturaremos o dado digitado neste campo de busca? E depois, como será realizada a filtragem deste valor? Em algum momento sabemos que este valor deverá cair em uma propriedade de PhotoListComponent, portanto criaremos em photo-list.component.ts a propriedade filter, do tipo string, que começa inicializada com uma string em branco. À medida em que formos digitando no input do navegador, o valor será atribuído a esta propriedade.
Qual é o evento do JavaScript podemos trabalhar para lidar com isso? Uma das opções é o keyup, disparado à medida em que digitamos. Para entendermos melhor, vamos supor que trabalhamos com JavaScript puro, e sem arrow function para facilitar a legibilidade:
h1.addEventListener('keyup', function(event) {
alert('oi')
});Com este código, a cada valor digitado pelo usuário no h1, acessado em DOM, será exibido um alerta. Por meio do event conseguimos acessar o valor de alert('oi'), sendo possível utilizarmos event.target.value para saber o que foi digitado.
Voltando ao código que estávamos escrevendo, indicaremos em keyup que filter receberá $event.target.value, o que se assemelha ao JavaScript puro que usamos de exemplo, com a diferença de que, no lugar de event, usamos $event do Angular, tratado e modificado.
<form>
<input
class="rounded"
type="search"
placeholder="search..."
autofocus
keyup="filter = $event.target.value"
>
</form>Então, a cada valor que for digitado no campo de busca, o valor do input será acessado usando-se a propriedade filter. No entanto, nada acontecerá, pois se mantermos o código assim, o Angular entenderá que estamos usando a string filter = $event.target.value dentro do evento keyup.
Já aprendemos que existe um tal de Data binding, então podemos supor que usar [keyup]="filter = $event.target.value" resolverá nosso problema, o que também não é o caso, já que este Data binding buscará a expressão entre aspas no componente, e este atributo não existe.
Para resolvermos isso, precisaremos realizar um Data binding que é um Event binding. Isto, no Angular, é feito colocando-se o nome do evento entre parênteses — (keyup)="filter = $event.target.value". Ou seja, para o evento keyup, a expressão "filter = $event.target.value" será avaliada.
Porém, esta associação de eventos se difere ao uso de colchetes, como em um Data binding regular, cujo dado vem da fonte de dados (componente) para o template, nunca o caminho inverso. Já quando utilizamos os parênteses, fazemos exatamente o oposto, isto é, o evento é disparado, indo da view do template para o componente.
É importante entendermos que estes bindings são unidirecionais, cada qual percorrendo um caminho diferente. Vamos salvar o projeto, abrir a página no navegador, consultar o console, em que não teremos nenhum erro. E para nos assegurarmos de que o campo de busca captura o termo digitado, incluiremos uma Expression language para a propriedade filter.
O código de photo-list.component.html ficará assim:
<div class="text-center mt-3 mb-3">
<form>
<input
class="rounded"
type="search"
placeholder="search..."
autofocus
(keyup)="filter = $event.target.value"
>
</form>
</div>
{{ filter }}
<ap-photos [photos]="photos"></ap-photos>Ao salvarmos tudo, voltarmos ao navegador e digitarmos "calopsita" (ou qualquer outro termo), à medida em que vamos digitando, a palavra vai se formando no layout antes da exibição das imagens. Deste modo temos certeza de que tudo está sendo adicionado por meio do binding de evento, e modificado no filter, atualizado conforme nossa digitação.
Quando abrimos a aplicação, um Data binding unidirecional ocorre, de filter para o template, e nada é exibido. Para que isso fique claro, podemos atribuir um valor inicial (flavio) temporariamente em filter: string = 'flavio' de photo-list.component.ts, e reabrir a página, e teremos "flavio" sendo exibido antes das imagens.
Agora, precisamos usar o valor que está no filter para de fato filtrarmos a lista. Faremos isto a seguir!